package com.imageim.yimirror.ui.activity;

import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.view.View;
import android.view.WindowManager;
import android.widget.ImageView;
import android.widget.RelativeLayout;
import android.widget.TextView;

import com.imageim.yimirror.R;
import com.imageim.yimirror.base.BaseActivity;
import com.imageim.yimirror.base.Constants;
import com.imageim.yimirror.bean.dailyPhoto.NoBgPhotoBean;
import com.imageim.yimirror.common.data.CommonData;
import com.imageim.yimirror.common.event.EventCode;
import com.imageim.yimirror.common.event.EventMessage;
import com.imageim.yimirror.common.network.NetUtil;
import com.imageim.yimirror.common.network.ThreadPoolManager;
import com.imageim.yimirror.common.network.constants.NetConstants;
import com.imageim.yimirror.common.network.listener.NetCallback;
import com.imageim.yimirror.common.network.tool.ParamCreator;
import com.imageim.yimirror.common.ui.SceneManager;
import com.imageim.yimirror.common.util.AnimUtil;
import com.imageim.yimirror.common.util.CacheUtils;
import com.imageim.yimirror.common.util.FaceDetectManager;
import com.imageim.yimirror.common.util.LogUtil;
import com.imageim.yimirror.common.util.PictureUtils;
import com.imageim.yimirror.common.util.UserUtil;
import com.martin.ads.omoshiroilib.debug.removeit.GlobalConfig;
import com.martin.ads.omoshiroilib.encoder.MediaCodecUtils;
import com.martin.ads.omoshiroilib.filter.helper.FilterType;
import com.martin.ads.omoshiroilib.flyu.fake.Logger;
import com.martin.ads.omoshiroilib.flyu.fake.LoggerFactory;
import com.martin.ads.omoshiroilib.flyu.hardcode.DemoConstants;
import com.martin.ads.omoshiroilib.flyu.hardcode.HardCodeData;
import com.martin.ads.omoshiroilib.flyu.hardcode.HardCodeHelper;
import com.martin.ads.omoshiroilib.flyu.openglfilter.common.FilterConstants;
import com.martin.ads.omoshiroilib.flyu.openglfilter.detector.DirectionDetector;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.base.FilterFactory;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.base.GPUImageFilter;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.base.GPUImageFilterGroupBase;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.changeface.ChangeFaceInfo;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.changeface.ChangeFaceNet;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.dstickers.DynamicStickerData;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.dstickers.DynamicStickerMulti;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.filtergroup.GPUImageFilterGroup;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.filtergroup.GPUImageMultiSectionGroup;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.filtergroup.MultiSectionInfo;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.multitriangle.DrawMultiTriangleNet;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.multitriangle.MultiTriangleInfo;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.switchface.CloneFaceFilter;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.switchface.SwitchFaceInfo;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.switchface.SwitchFaceNet;
import com.martin.ads.omoshiroilib.flyu.openglfilter.gpuimage.switchface.TwoPeopleSwitch;
import com.martin.ads.omoshiroilib.flyu.sdk.mediaplayer.AudioFocusCore;
import com.martin.ads.omoshiroilib.glessential.CameraView;
import com.martin.ads.omoshiroilib.glessential.GLRootView;
import com.martin.ads.omoshiroilib.ui.CaptureAnimation;
import com.martin.ads.omoshiroilib.ui.face.FaceWrapper;
import com.martin.ads.omoshiroilib.util.BitmapUtils;
import com.martin.ads.omoshiroilib.util.FileUtils;

import org.apache.http.message.BasicNameValuePair;
import org.json.JSONException;

import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import static com.martin.ads.omoshiroilib.util.AnimationUtils.displayAnim;

/**
 * 试穿留影倒计时拍照页面
 */
public class TakeMomeryPhotoActivity extends BaseActivity implements GPUImageFilterGroupBase.IGroupStateChanged {
    private final static Logger log = LoggerFactory.getLogger();

    private CameraView cameraView;
    private CaptureAnimation captureAnimation;
    private int surfaceWidth, surfaceHeight;
    private boolean canUseMediaCodec;
    private GLRootView glRootView;
    public static final double preferedRatio = 4.0 / 3;
    private Timer timer;
    private int timerCount;
    private View ivCamera;
    private TextView tvTimeCount;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        init();
    }

    private void init() {
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN);
        WindowManager.LayoutParams params = getWindow().getAttributes();
        params.flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
        getWindow().setAttributes(params);

        glRootView = findViewById(R.id.camera_view);
        cameraView = new CameraView(this, glRootView, preferedRatio);

        cameraView.setScreenSizeChangedListener(new CameraView.ScreenSizeChangedListener() {
            @Override
            public void updateScreenSize(int width, int height) {
                //                Log.d(TAG, "updateScreenSize: " + redPacketWidth + " " + redPacketHeight);
                surfaceWidth = width;
                surfaceHeight = height;
                int w = (int) (screenHeight * (1 / preferedRatio));
                int h = screenHeight;
                captureAnimation.resetAnimationSize(w, h);
            }
        });

        captureAnimation = findViewById(R.id.capture_animation_view);
        int w = (int) (screenHeight * (1 / preferedRatio));
        int h = screenHeight;
        RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(w, h);
        lp.addRule(RelativeLayout.CENTER_IN_PARENT);
        captureAnimation.setLayoutParams(lp);

        canUseMediaCodec = MediaCodecUtils.checkMediaCodecVideoEncoderSupport() == MediaCodecUtils.CODEC_SUPPORTED
                &&
                MediaCodecUtils.checkMediaCodecAudioEncoderSupport() == MediaCodecUtils.CODEC_SUPPORTED;

        HardCodeHelper.decompressAllResource(this);
        initUIandEvent();
        // abcde美颜级别依次减弱
        cameraView.getGlRender().switchLastFilterOfCustomizedFilters(FilterType.BEAUTIFY_A);
        showCameraAnim();
        initTakePhoto();
    }


    private void initTakePhoto() {
        tvTimeCount = findViewById(R.id.tv_time_count);
    }


    private void takePhoto() {
        timerCount = maxCount;
        timer = new Timer();
        tvTimeCount.setVisibility(View.GONE);
        timer.scheduleAtFixedRate(new TimerTask() {
            @Override
            public void run() {
                runOnUiThread(() -> {
                    if (timerCount == 0) {
                        tvTimeCount.setVisibility(View.GONE);
                        takePic();
                        timer.cancel();
                        timer = null;
                    } else {
                        tvTimeCount.setVisibility(View.VISIBLE);
                        tvTimeCount.setText(String.valueOf(timerCount));
                        displayAnim(tvTimeCount, mContext, R.anim.anim_text_scale, View.VISIBLE);
                    }
                    timerCount--;
                });
            }
        }, 5000, 1000);
    }

    private void takePic() {
        captureAnimation.setVisibility(View.VISIBLE);
        captureAnimation.startAnimation();
        // showLoading();
        cameraView.getGlRender().addRunnableOnDrawEnd(new Runnable() {
            @Override
            public void run() {
                BitmapUtils.sendImage(
                        surfaceWidth,
                        surfaceHeight,
                        mContext,
                        new FileUtils.FileSavedCallback() {
                            @Override
                            public void onFileSaved(String filePath) {
                                //  hideLoading();
                                if (!GlobalConfig.PREVIEW_WHEN_SHOT) {
                                    return;
                                }
                                Bundle data = new Bundle();
                                data.putString("photoPath", filePath);
                                if (toDoAction == Constants.Action.UPLOAD_DAILY_PHOTO_RECORD || toDoAction == Constants.Action.CLIP_BIG_SIZE_PHOTO
                                        || toDoAction == Constants.Action.CLIP_SMALL_SIZE_PHOTO) {
                                    data.putInt(Constants.TO_DO_FLAG, toDoAction);
                                    SceneManager.toScene(mContext, ClipPhotoActivity.class, data);
                                }
//                                else {
//                                    SceneManager.toScene(mContext, TakePhotoOrUserPhotoActivity.class, data);
//                                }
                            }
                        }
                );
            }
        });
    }

    private void uploadUserPhoto(String filePath) {
        new DealPhotoTask(filePath).executeOnExecutor(ThreadPoolManager.getInstance().getThreadPool());
    }

    private class DealPhotoTask extends AsyncTask<Void, Void, Bitmap> {
        private String filePath;

        public DealPhotoTask(String filePath) {
            this.filePath = filePath;
        }

        @Override
        protected Bitmap doInBackground(Void... voids) {
//            Bitmap photoBitmap = PictureUtils.getImage(filePath);
            Bitmap photoBitmap = BitmapUtils.loadBitmapFromFile(filePath);
            // 裁剪后的bitmap
            Bitmap clipedBitmap = FaceDetectManager.getInstance().clipBody(photoBitmap);
            return clipedBitmap;
        }

        @Override
        protected void onPostExecute(Bitmap clipedBitmap) {
            hideLoading();
            if (clipedBitmap != null) {
                upload(clipedBitmap);
            } else {
                 if (repeatCount < 4) {
                     takePhoto(); // 从新拍
                     repeatCount++;
                 } else {
                     finish();
                 }
            }
        }
    } // DealPhotoTask

    private int repeatCount = 0;

    private void upload(Bitmap clipedBitmap) {
        List<BasicNameValuePair> params = new ParamCreator()
                .add("userPhoto", BitmapUtils.bitmapToBase64(clipedBitmap, 100))
                .add(Constants.USER_ID, UserUtil.getUserId())
                .build();
        NetUtil.postObject(mContext, NetConstants.URL.UPLOAD_IMAGE_PHOTO, params, new NetCallback<NoBgPhotoBean>() {
            @Override
            public void onStart() {

            }

            @Override
            public void onSuccess(NoBgPhotoBean result) {
//                ImageView ivPhoto = findViewById(R.id.iv_result_bitmap);
//                ivPhoto.setImageBitmap(BitmapUtils.base64ToBitmap(result.getBodyCutImg()));
            }

            @Override
            public void onFail(int errorCode, String errorMsg) {
                toast(errorMsg + errorCode);
            }
        }, NoBgPhotoBean.class);
    }

    @Override
    public void onEventMainThread(EventMessage event) {
        super.onEventMainThread(event);
        switch (event.getCode()) {
            case EventCode.CODE_FINISH:
                finish();
                break;
            case EventCode.CODE_HIDE_CAMERA_ANIM:
                AnimUtil.scaleToDismiss(ivCamera);
                break;
            default:
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (cameraView != null) {
            cameraView.onPause();
        }
    }

    @Override
    protected void onResume() {
        super.onResume();
        if (cameraView != null) {
            cameraView.onResume();
        }
        takePhoto();
    }

    @Override
    protected void onDestroy() {
        super.onDestroy();
        if (cameraView != null) {
            cameraView.onDestroy();
        }
        if (timer != null) {
            timer.cancel();
            timer = null;
        }
        deInitUIandEvent();
    }

    private int maxCount = 5;

    @Override
    protected void initBundle() {
        boolean hasToDoAction = getIntent().hasExtra(Constants.TO_DO_FLAG);
        if (hasToDoAction) {
            toDoAction = getIntent().getIntExtra(Constants.TO_DO_FLAG, 0);
            if (toDoAction == Constants.Action.UPLOAD_DAILY_PHOTO_RECORD) {
                //                playSound();
            } else if (toDoAction == Constants.Action.CLIP_BIG_SIZE_PHOTO ||
                    toDoAction == Constants.Action.CLIP_SMALL_SIZE_PHOTO) {
                maxCount = 3;
            }
        }
    }


    @Override
    protected int getLayoutId() {
        return R.layout.activity_take_memory_photo;
    }

    @Override
    protected void initView() {
        findViewById(R.id.btn_close).setOnClickListener(v -> finish());
    }

    @Override
    protected void initData() {

    }

    private void showCameraAnim() {
        ivCamera = findViewById(R.id.iv_anim_camera);
        AnimUtil.scaleUp(ivCamera);
    }


    protected DirectionDetector mDirectionDetector;

    protected GPUImageFilterGroupBase mCurrentFilter;

    private int mMaxFaceCount = 1;

    private FaceWrapper faceWrapper;

    private void deinitVDM() {
        if (null != mDirectionDetector) {
            mDirectionDetector.stop();
            mDirectionDetector = null;
        }

        if (null != faceWrapper) {
            faceWrapper.uninit();
            faceWrapper = null;
        }
        mCurrentFilter = null;
    }

    private void doUpdateFilter(HardCodeData.EffectItem item) {
        GPUImageFilterGroupBase filterGroup = parseEffect(item.type, DemoConstants.APPDIR + "/" + item.unzipPath);

        filterGroup.setGroupStateChangedListener(this);
        if (null != faceWrapper) {
            mCurrentFilter = filterGroup;
            mCurrentFilter.setPhoneDirection(mDirectionDetector.getDirection());
            faceWrapper.setFilter(mCurrentFilter);
        }

        if (mMaxFaceCount > FilterConstants.MAX_FACE_COUNT) {
            mMaxFaceCount = FilterConstants.MAX_FACE_COUNT;
        }

        if (null != faceWrapper && null != faceWrapper.getGlRender()) {
            faceWrapper.getGlRender().switchDetectMaxFaceCount(mMaxFaceCount);
        }
    }


    public final static int TYPE_CHANGE_FACE = 0;
    public final static int TYPE_DYNAMIC_STICKER = 1;
    public final static int TYPE_SWITCH_FACE = 2;
    public final static int TYPE_MULTI_SECTION = 3;
    public final static int TYPE_MULTI_TRIANGLE = 4;  // 注意强制更新的内容
    public final static int TYPE_TWO_PEOPLE_SWITCH = 5;
    public final static int TYPE_CLONE_PEOPLE_FACE = 6;

    protected GPUImageFilterGroupBase parseEffect(int type, String unzipPath) {
        GPUImageFilterGroupBase groupBase = new GPUImageFilterGroup();
        groupBase.addFilter(new GPUImageFilter());
        if (type < 0)
            return groupBase;
        try {
            if (type == TYPE_CHANGE_FACE) {
                ChangeFaceInfo changeFaceInfo = FilterFactory.readChangeFaceInfo(unzipPath);
                groupBase.addFilter(new ChangeFaceNet(unzipPath, changeFaceInfo));
            } else if (type == TYPE_DYNAMIC_STICKER) {
                DynamicStickerData data = FilterFactory.readDynamicStickerData(unzipPath);
                groupBase.addFilter(new DynamicStickerMulti(unzipPath, data));
            } else if (type == TYPE_SWITCH_FACE) {
                SwitchFaceInfo switchFaceInfo = FilterFactory.readSwitchFaceData(unzipPath);
                groupBase.addFilter(new SwitchFaceNet(unzipPath, switchFaceInfo));
            } else if (type == TYPE_MULTI_SECTION) {
                MultiSectionInfo multiSectionInfo = FilterFactory.readMultiSectionData(unzipPath);
                groupBase = new GPUImageMultiSectionGroup(unzipPath, multiSectionInfo);
                groupBase.addFilter(new GPUImageFilter());
            } else if (type == TYPE_MULTI_TRIANGLE) {
                MultiTriangleInfo info = FilterFactory.readMultiTriangleInfo(unzipPath);
                groupBase.addFilter(new DrawMultiTriangleNet(unzipPath, info));
            } else if (type == TYPE_TWO_PEOPLE_SWITCH) {
                groupBase.addFilter(new TwoPeopleSwitch());
            } else if (type == TYPE_CLONE_PEOPLE_FACE) {
                groupBase.addFilter(new CloneFaceFilter());
            }
        } catch (IOException e) {
            log.error("read effect filter data failed, " + e.getMessage());
        } catch (JSONException e) {
            log.error("parse effect filter data failed, " + e.getMessage());
        }
        return groupBase;
    }

    protected void initUIandEvent() {
        // init faceu related
        AudioFocusCore.initialize(mContext);
        mCurrentFilter = new GPUImageFilterGroup();
        mCurrentFilter.addFilter(new GPUImageFilter());
        if (null == mDirectionDetector) {
            mDirectionDetector = new DirectionDetector(this, false);
            mDirectionDetector.start();
        }
        log.info("init camera start");

        // GPUVideoViewDecorator 是先做的翻转，再做的旋转
        faceWrapper = new FaceWrapper(this, cameraView.getGlRender());
        faceWrapper.setDirectionDetector(mDirectionDetector);
        faceWrapper.getGlRender().setUpCamera(cameraView.getCameraEngine().getDisplayRotate(),
                cameraView.getGlRender().isCameraFacingFront(), false);

        doUpdateFilter(HardCodeData.itemList.get(0));
    }

    protected void deInitUIandEvent() {
        deinitVDM();
    }

    @Override
    public void onTipsAndCountChanged(int maxCount, final String tips, final int duration) {
        mMaxFaceCount = maxCount;
        if (null != faceWrapper && null != faceWrapper.getGlRender()) {
            faceWrapper.getGlRender().switchDetectMaxFaceCount(mMaxFaceCount);
        }
        LogUtil.d("onTipsAndCountChanged ", maxCount + " " + tips + " " + duration);
    }

    @Override
    public boolean isSupportSwipeBack() {
        return false;
    }
}